#include "evm_module.h"

#include "curl/curl.h"
#include <sys/stat.h>
#include <evue_curl.h>

#define ACCEPT "Accept: application/json"
#define CONTENT_TYPE "Content-Type: application/json"
#define CHARSET "charsets: utf-8"


#include "pthread.h"

typedef struct http_struct{
    char *method;
    char *url;
    char *header;
    char *data;
    int timeout;
    pthread_t fd;
    evm_event_msg_t *msg;
}http_struct_t;


static size_t header_callback(char *buffer, int size, int nitems, void *private_data)
{
    int length = length = nitems*size;

    msg_buffer_t *data = (msg_buffer_t*)private_data;
    if(data == NULL)
        return 0;
    if ((data->len + length) <= WEBCLIENT_HEADER_BUFSZ)
    {
        memcpy((void*)(data->data + data->len), (const void*)buffer, length);
        data->len += length;
    }
    else
    {
        evm_print("<-- No more buffer, discard data (len:%d) -->\r\n", length);
    }
    return length;
}

static size_t data_callback(char *buffer, int size, int nitems, void *private_data)
{
    int length = nitems*size;

    msg_buffer_t *data = (msg_buffer_t*)private_data;
    if(data == NULL)
        return 0;
    if ((data->len + length) <= WEBCLIENT_RESPONSE_BUFSZ)
    {
        memcpy((void*)(data->data + data->len), (const void*)buffer, length);
        data->len += length;
    }
    else
    {
        evm_print("<-- No more buffer, discard data (len:%d) -->\r\n", length);
    }
    return length;
}

static void *curl_callback(void *args){
    http_struct_t *http =(http_struct_t *)args;
    evm_event_msg_t *msgbuff = (evm_event_msg_t *)http->msg;
    http_response_t *resp = (http_response_t*)msgbuff->data;

    struct curl_slist *headers=NULL;
    char *ptr= http->header;

    char *method = strupr((char *)http->method);

    int headlen = strlen(http->header);
    int headindex = 0,headcnt = 1;
//    if(http->header!=NULL)
    {
        char delims[7] = {0};
        sprintf(delims, "head%d=\"", headcnt++);
        char *paddr = strstr(ptr, delims);
        while(paddr){
            char *startaddr = paddr + 7,*endaddr = NULL;
            sprintf(delims, "head%d=\"", headcnt++);
            paddr = strstr(ptr, delims);
            endaddr = paddr;
            if(endaddr)
                endaddr = endaddr - 2;
            else
                endaddr = http->header + headlen - 1;
            int _len = endaddr - startaddr;

            char *_header = evm_malloc(_len+1);
            memset(_header, 0, _len);
            memcpy(_header, startaddr, _len);
            _header[_len] = '\0';
            headers = curl_slist_append(headers, _header);
            evm_free(_header);
        }
    }

    CURLcode res = CURLE_OK;
    int http_code = 0;
    CURL *curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_URL, http->url);

        if(!strcmp(http->method,"POST")){
            if (http->data){
                curl_easy_setopt(curl, CURLOPT_POSTFIELDS,http->data);
                curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,strlen(http->data));
            }
            curl_easy_setopt(curl, CURLOPT_POST, 1);
        }

        if(!strcmp(method,"PUT"))
            curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

        curl_easy_setopt(curl, CURLOPT_TIMEOUT, http->timeout);

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);

        /* send all data to this function  */
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, data_callback);
        /* we pass our 'chunk' struct to the callback function */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp->data);

        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, resp->header);

        /* some servers don't like requests that are made without a user-agent
        field, so we provide one */
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");

        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

        curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 1024 * 1024 * 1024L);
        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);

        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

        /* Check for errors */
        if(res != CURLE_OK){
            // todo free
            evm_print("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
            goto end;
        }
        resp->code = http_code;
        /* always cleanup */
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        evm_module_msg_put(msgbuff, 0);
    }
end:
    //todo free
    pthread_exit(NULL);
}

int evm_adaptor_http_request(const char* method, const char* url, const char* header, const char* body, const char *responseType, int timeout, void *msg)
{
    http_struct_t *http = evm_malloc(sizeof(http_struct_t));

    http->method = (char *)method,
    http->url = (char *)url,
    http->header = (char *)header,
    http->data = (char *)body,
    http->timeout = timeout,
    http->msg = msg;

    http_response_t *resp = http->msg->data;
    resp->data = evm_malloc(sizeof (msg_buffer_t));
    if(resp->data == NULL)
        return -1;
    resp->data->data = evm_malloc(WEBCLIENT_RESPONSE_BUFSZ);
    if(resp->data->data == NULL)
        return -1;
    memset(resp->data->data, 0, WEBCLIENT_RESPONSE_BUFSZ);
    resp->data->len = 0;

    resp->header = evm_malloc(sizeof (msg_buffer_t));
    if(resp->header == NULL)
        return -1;
    resp->header->data = evm_malloc(WEBCLIENT_HEADER_BUFSZ);
    memset(resp->header->data, 0, WEBCLIENT_HEADER_BUFSZ);
    resp->header->len = 0;


    curl_global_init(CURL_GLOBAL_ALL);

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,  PTHREAD_CREATE_DETACHED);
    if ((pthread_create(&http->fd, &attr, curl_callback, http)) == -1)
    {
        evm_print("create error!\n");
        return -1;
    }
    return 0;
}


int evm_module_http_init(void){

    return 0;
}


void evm_module_http_destory(void){


}
